package buildtools;

import javax.vecmath.Point3d;

import math.Precision;
import node.GeoData;
import node.GeoNode;

import component.AbstractComponent;
import component.Ball;
import component.ComponentFactory;
import component.Structure;
import component.Tube;
import component.group.ComponentGroup;

public abstract class StructureBuilder {

	protected final Structure structure;
	protected final ComponentFactory factory;
	
	protected ComponentGroup temporaryGroup = null;
	
	protected final Connector connector;

	public StructureBuilder(Structure structure, ComponentFactory factory) {
		super();
		this.structure = structure;
		this.factory = factory;
		this.connector = new Connector(structure);
	}
	
	protected Ball findBallAt(Point3d pos) {
		for (GeoNode node : structure.getPermanentGeoGroup().getGeoNodes()) {
			if (node.getComponent() instanceof Ball && Precision.compare(pos, node.getPos())) {
				return (Ball)node.getComponent();
			}
		}
		return null;
	}
	
	protected Tube findTubeAt(Point3d p1, Point3d p2) {
		for (GeoNode node : structure.getPermanentGeoGroup().getGeoNodes()) {
			if (node.getComponent() instanceof Tube) {
				Tube tube = (Tube)node.getComponent();
				if ( (Precision.compare(p1, tube.getPos()) && Precision.compare(p2, tube.getSecondaryPosition()))
						|| (Precision.compare(p2, tube.getPos()) && Precision.compare(p1, tube.getSecondaryPosition())) ) {
					return tube;
				}
			}
		}
		return null;
	}
	
	protected boolean ballsAreConnected(Ball b1, Ball b2) {
		Tube tube = findTubeAt(b1.getPos(), b2.getPos());
		return (tube != null && b1.isConnectedTo(tube) && b2.isConnectedTo(tube));
	}
	
	protected boolean canConnectBalls(Ball b1, Ball b2) {
		if (b1 == b2)
			return false;
		if (!Precision.compare(b1.getPos().distance(b2.getPos()), GeoData.BALL_DISTANCE))
			return false;
		if (this.ballsAreConnected(b1, b2))
			return false;
		return true;
	}
	
	public void clearTemporary() {
		if (temporaryGroup != null) {
			temporaryGroup.disposeAll();
			temporaryGroup = null;
		}
	}
	
	public boolean isTemporary(AbstractComponent component) {
		return (temporaryGroup != null && temporaryGroup.contains(component));
	}
	
	public abstract void temporaryClicked(AbstractComponent component);
	
	
}
